﻿// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Media;

using Nova.CodeDOM;

namespace Nova.UI
{
    /// <summary>
    /// The view model for a <see cref="CodeDOM.SymbolicRef"/>.
    /// </summary>
    public abstract class SymbolicRefVM : ExpressionVM
    {
        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create a view model instance for the specified <see cref="CodeDOM.SymbolicRef"/>.
        /// </summary>
        protected SymbolicRefVM(SymbolicRef symbolicRef, Dictionary<CodeObject, CodeObjectVM> dictionary)
            : base(symbolicRef, dictionary)
        { }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The underlying <see cref="CodeDOM.SymbolicRef"/> model.
        /// </summary>
        public SymbolicRef SymbolicRef
        {
            get { return (SymbolicRef)CodeObject; }
        }

        #endregion

        #region /* METHODS */

        #endregion

        #region /* RENDERING */

        protected internal override bool HasBorder()
        {
            return false;
        }

        protected virtual Brush RenderBrush(RenderFlags flags)
        {
            return IDENTIFIER_BRUSH;
        }

        public override void RenderExpression(CodeRenderer renderer, RenderFlags flags)
        {
            renderer.RenderText(SymbolicRef.Name, RenderBrush(flags), this);
        }

        public override void RenderToolTip(CodeRenderer renderer, RenderFlags flags)
        {
            TypeRefBaseVM.RenderType(renderer, CodeObject.GetType(), flags, this);
            renderer.RenderRightArrow(NORMAL_BRUSH, this);
            RenderReferenceDescription(renderer, SymbolicRef.Reference);
            RenderSummaryCommentInToolTip(renderer);
            RenderMessagesInToolTip(renderer, flags);
        }

        protected virtual void RenderReferenceDescription(CodeRenderer renderer, object obj)
        {
            RenderDescription(renderer, obj, this);
        }

        public static void RenderDescription(CodeRenderer renderer, object obj, CodeObjectVM tag)
        {
            if (obj is CodeObject)
            {
                // Create a VM (used when displaying Possible Matches for an UnresolvedRef)
                CodeObject codeObject = (CodeObject)obj;
                CodeObjectVM codeObjectVM = CreateVM(codeObject, null, true);
                codeObjectVM.RenderDescription(renderer);
                if (tag == null)
                    tag = codeObjectVM;

                // Hacky - set the Border tag to anything passed in (to display Messages for Possible Matches)
                Border border = codeObjectVM.GetSelectionElement() as Border;
                if (border != null)
                    border.Tag = tag;
            }
            else if (obj is MemberInfo)
            {
                MemberInfo memberInfo = (MemberInfo)obj;
                RenderDescription(renderer, memberInfo, tag);
                RenderReferencedAssembly(renderer, "in", memberInfo.Module.Assembly);
            }
            else if (obj is ParameterInfo)
            {
                ParameterInfo parameterInfo = (ParameterInfo)obj;
                ParameterRefVM.RenderParameterInfo(renderer, parameterInfo, RenderFlags.ForceBorder | RenderFlags.ShowParentTypes, tag);
                RenderReferencedAssembly(renderer, "in", parameterInfo.Member.Module.Assembly);
            }
        }

        protected static void RenderDescription(CodeRenderer renderer, MemberInfo memberInfo, CodeObjectVM parentVM)
        {
            const RenderFlags flags = RenderFlags.ForceBorder | RenderFlags.ShowParentTypes;
            switch (memberInfo.MemberType)
            {
                case MemberTypes.TypeInfo:
                case MemberTypes.NestedType:
                    TypeRefBaseVM.RenderType(renderer, (Type)memberInfo, flags | RenderFlags.Description, parentVM);
                    break;
                case MemberTypes.Constructor:
                    ConstructorRefVM.RenderConstructorInfo(renderer, (ConstructorInfo)memberInfo, flags, parentVM);
                    break;
                case MemberTypes.Method:
                    MethodRefVM.RenderMethodInfo(renderer, (MethodInfo)memberInfo, flags, parentVM);
                    break;
                case MemberTypes.Property:
                    PropertyRefVM.RenderPropertyInfo(renderer, (PropertyInfo)memberInfo, flags, parentVM);
                    break;
                case MemberTypes.Field:
                    FieldRefVM.RenderFieldInfo(renderer, (FieldInfo)memberInfo, flags, parentVM);
                    break;
                case MemberTypes.Event:
                    EventRefVM.RenderEventInfo(renderer, (EventInfo)memberInfo, flags, parentVM);
                    break;
                default:
                    renderer.RenderText(memberInfo.ToString(), IDENTIFIER_BRUSH, parentVM);
                    break;
            }
        }

        protected static void RenderReferencedAssembly(CodeRenderer renderer, string prefix, Assembly assembly)
        {
            AssemblyName assemblyName = assembly.GetName();
            renderer.RenderText(" (" + prefix + " " + assemblyName.Name + " " + assemblyName.Version.Major + "." + assemblyName.Version.Minor + ")", NORMAL_BRUSH, TextStyle.Proportional);
        }

        #endregion
    }
}
